#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>


#define GPIO_PIN    112
int irq_num;
// struct tasklet_struct my_tasklet;

extern void open_softirq(int nr, void (*action)(struct softirq_action *));
extern void raise_softirq(unsigned int nr);

// 中断上文
irqreturn_t test_irq_handler(int irq, void *args)
{
    printk(KERN_EMERG "This is irq_interrupt\r\n");
    // // 调度中断下文
    // tasklet_schedule(&my_tasklet);
    raise_softirq(TEST_SOFTIRQ);
    
    return IRQ_RETVAL(IRQ_HANDLED);
}


// // 中断下文tasklet处理函数
// void my_tasklet_callback(struct tasklet_struct *tasklet)
// {
//     printk(KERN_EMERG "data is %ld\n", tasklet->data);
//     tasklet->data ++;

//     // 禁止使用休眠函数，否则会导致内核崩溃！！！！
//     // msleep(10);
// }

void my_softirq_action(struct softirq_action *act)
{
    printk(KERN_EMERG "This is my_softirq_action\r\n");
}


static int __init gpio_irq_init(void)
{
    int ret;
    printk(KERN_EMERG "init gpio interrupt driver\r\n");

    // 获取引脚中断号
    irq_num = gpio_to_irq(GPIO_PIN);
    printk(KERN_EMERG "gpio (%d) mapped to IRQ (%d)\r\n", GPIO_PIN, irq_num);

    // 请求中断
    ret = request_irq(irq_num, test_irq_handler, IRQF_TRIGGER_RISING, "test", NULL);
    if (ret < 0)
    {
        printk(KERN_EMERG "request_irq error\r\n");
        return -1;
    }
    printk(KERN_EMERG "request_irq ok\r\n");

    // 注册软中断
    open_softirq(TEST_SOFTIRQ, my_softirq_action);
    printk(KERN_EMERG "open_softirq ok\r\n");


    return 0;
}


static void __exit gpio_irq_exit(void)
{
    // // 销毁tasklet之前，应该确保该tasklet已经被停止！！
    // tasklet_disable(&my_tasklet);
    // // tasklet_enable(&my_tasklet);
    // tasklet_kill(&my_tasklet);
    // 释放中断号
    free_irq(irq_num, NULL);
    printk(KERN_EMERG "module exit\r\n");
}


module_init(gpio_irq_init);
module_exit(gpio_irq_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Treasure1029");